'/
' MOTEP - Massive Online Text Environment Project
' --------------------------------------------------------------------------------
' Shared Code
' 
' World.bmx
' 
' (c) Anton Berlin. All Rights Reserved.
'/


const SPACE_LIMIT_X:int = 2000
const SPACE_LIMIT_Y:int = 2000
const SPACE_LIMIT_Z:int = 50
const DEFAULT_POS_X:int = 1000
const DEFAULT_POS_Y:int = 1000
const DEFAULT_POS_Z:int = 25
const DESCR_LINE_LIMIT:int = 30
const NULL_DATA:string = "!!NULL!!"



'// TBase is the base object. Every object is derived from TBase. You MUST call the Construct() method every time
'// you create an object for it to receive a proper guid. Always use the GetGUID() method to retrieve the guid of
'// the object.
type TBase abstract

'*** public:

	method Construct:byte() 
	
		guid = guid + 1
		m_guid = guid
		return 1
	
	end method
	
	method GetGUID:int() abstract
	
	field m_guid:int

'*** private:

	global guid:int

end type

'// TWorld is the world object. There is only supposed to be one instance of this object, unless you want parallell
'// worlds. In this object you store regions. Remember to call Construct() after you create this object.
type TWorld extends TBase

	'// Access a TRegion from the list in the TWorld object.
	method AccessRegion:TRegion(regionID:int)
	
		if (not regionID) ..
			return null
		
		local r:TRegion
		
		for local i:TRegion = eachin m_regions
		
			if (i.GetRegionID() = regionID) then
			
				r = i
				exit
			
			end if
		
		next
		
		return r
	
	end method
	
	'// Return GUID.
	method GetGUID:int(); return m_guid; end method
	
	'// Add a region to the TWorld object.
	method AddRegion:byte(rgn:object) 
	
		if (not TRegion(rgn)) ..
			return 0
		ListAddLast(m_regions, rgn)
		return 1
	
	end method
	
	'// Remove a region with a specific region-id.
	method RemoveRegion:byte(regionID:int)
	
		if (not regionID) ..
			return 0
		
		local r:TRegion = null
		
		for local i:TRegion = eachin m_regions
		
			if (i.GetRegionID() = regionID) then
			
				r = i
				exit
			
			end if
		
		next
		
		if (r = null) then
		
			return 0
		
		else
		
			ListRemove(m_regions, r)
			return 1
		
		end if
	
	end method
	
	field m_regions:TList = CreateList()

end type

'// TRegion is the object used for regions. Every region contains the possibility of 20000x20000x20000 rooms. Each
'// region has their own object list as well. This does not include the objects that players carry though. Every
'// TRegion is connected to the TWorld object.
type TRegion extends TBase

'*** public:

	'// Construct the object.
	method Construct:byte()
	
		if (super.Construct()) then
		
			regionID = regionID + 1
			m_id = regionID
			return 1
		
		else
		
			return 0
		
		end if
	
	end method
	
	'// Return GUID.
	method GetGUID:int(); return m_guid; end method
	
	'// Load settings from the database.
	method LoadSettings:byte()
	
		' <-- Code for loading settings from the database!
		return 1
	
	end method
	
	'// Get the region-id of this region.
	method GetRegionID:int(); return m_id; end method
	
	'// Get global object list.
	method GetGlobalObjectList:TList(); return m_globalObjList; end method
	
	'// Access a room object that resides in this region.
	method AccessRoom:TRoom(x:int = DEFAULT_POS_X, y:int = DEFAULT_POS_Y, z:int = DEFAULT_POS_Z)
	
		return m_pos[x, y, z]
	
	end method
	
	'// Check if a room exists.
	method RoomExists:byte(x:int, y:int, z:int)
	
		if (m_pos[x, y, z] = null) ..
			return 0 ..
		else ..
			return 1
	
	end method
	
	'// Add a room (to this TRegion object) from the room database.
	method AddRoom:byte(roomID:int, x:int = DEFAULT_POS_Y, y:int = DEFAULT_POS_X, z:int = DEFAULT_POS_Z)
	
		local i:TRoom = new TRoom
		
		if (i.Construct()) then
		
			if (m_pos[x, y, z] <> null) ..
				return 0
			m_pos[x, y, z] = i
			return 1
		
		else
		
			return 0
		
		end if
	
	end method
	
	'// Remove a room from this TRegion.
	method RemoveRoom:byte(x:int, y:int, z:int)
	
		if (not x or not y or not z) ..
			return 0
		m_pos[x, y, z] = null
	
	end method
	
	'// Create a new object in this region. Use the object-id from the
	'// database to identify which object to create.
	method CreateObject:byte(objectID:int, x:int = -1, y:int = -1, z:int = -1)
	
		local i:TObject = new TObject
		if (i.Construct()) then
		
			if (x > SPACE_LIMIT_X or y > SPACE_LIMIT_Y or z > SPACE_LIMIT_Z) then
			
				return 0
			
			else
			
				local j = false
				
				if (x < 0 and y < 0 and z < 0) then
				
					j = true
				
				else
				
					if (MoveObjectToRoom(i, x, y, z)) ..
						j = true
				
				end if
				
				if (j = true) then
				
					i.SetName("Obj" + i.GetGUID())
					ListAddLast(m_globalObjList, i)
					return 1
				
				else
				
					return 0
				
				end if
			
			end if
		
		else
		
			return 0
		
		end if
	
	end method
	
	'// Add an object to the list of objects in this TRegion, and place it, if needed.
	method AddObject:byte(obj:object, x:int = -1, y:int = -1, z:int = -1)
	
		if (not TObject(obj)) ..
			return 0
		ListAddLast(m_globalObjList, obj)
		return 1
	
	end method
	
	'// Delete an object.
	method RemoveObject:byte(obj:object)
	
		if (not TObject(obj)) ..
			return 0
		
		local o:TObject = null
		
		for local i:TObject = eachin m_globalObjList
		
			if (i = obj) then
			
				o = i
				exit
			
			end if
		
		next
		
		if (o = null) then
		
			return 0
		
		else
		
			ListRemove(m_globalObjList, o)
			return 1
		
		end if
	
	end method
	
	'// Access an object using a specific guid.
	method AccessObject:TObject(GUID:int)
	
		if (not GUID) ..
			return null
		
		local o:TObject = null
		
		for local i:TObject = eachin m_globalObjList
		
			if (i.m_guid = GUID) then
			
				o = i
				exit
			
			end if
		
		next
		
		return o
	
	end method
	
	'// Move an object to another room.
	method MoveObjectToRoom:byte(obj:TObject, x:int, y:int, z:int)
	 
		if (not x or not y or not z) ..
			return 0
		if (obj.GetPosX() = x and obj.GetPosY() = y and obj.GetPosZ() = z) ..
			return 0
		
		if (AccessRoom(x, y, z).AddObject(obj)) ..
			return 1 ..
		else ..
			return 0
	
	end method
	
	field m_id:int
	field m_pos:TRoom[SPACE_LIMIT_X + 1, SPACE_LIMIT_Y + 1, SPACE_LIMIT_Z + 1]
	field m_globalObjList:TList = CreateList()

'*** private:

	global regionID:int

end type

'// TObject is the object used as the template for all the objects in the game, such as gear, npc's, mobs, trees,
'// etc. Every TObject is connected to a TRegion. m_id stores the id of the object used to identify it in the
'// database. The id has to be > 0 to be in the database.
type TObject extends TBase

	'// Construct the object.
	method Construct:byte()
	
		if (super.Construct()) then
		
			m_descr = NULL_DATA
			return 1
		
		else
		
			return 0
		
		end if
	
	end method
	
	'// Return GUID.
	method GetGUID:int(); return m_guid; end method
	
	'// Access a TObject from the local object list in this object (using a
	'// GUID to identify the object).
	method AccessObject:TObject(ObjGUID:int)
	
		if (not ObjGUID) ..
			return null
		
		local o:TObject
		
		for local i:TObject = eachin m_localObjList
		
			if (i.GetGUID() = ObjGUID) then
			
				o = i
				exit
			
			end if
		
		next
		
		return o
	
	end method
	
	'// Return the database-id of the object.
	method GetDatabaseIdentifier(); return m_id; end method
	
	'// Return the current owner of this object (like a room, an npc, a mob, a player, a chest, etc).
	method GetOwner:TObject(); return m_currentOwner; end method
	
	'// Return the current X-axis of the position of the object.
	method GetPosX:int(); return m_posX; end method
	
	'// Return the current Y-axis of the position of the object.
	method GetPosY:int(); return m_posY; end method
	
	'// Return the current Z-axis of the position of the object.
	method GetPosZ:int(); return m_posZ; end method
	
	'// Set the current X-axis of the position of the object.
	method SetPosX(n:int); m_posX = n; end method
	
	'// Set the current Y-axis of the position of the object.
	method SetPosY(n:int); m_posY = n; end method
	
	'// Set the current Z-axis of the position of the object.
	method SetPosZ(n:int); m_posZ = n; end method
	
	'// return locally stored objects as a linked list.
	method GetLocalObjectList:TList(); return m_localObjList; end method
	
	'// Add an object to this object's local list (so that this object OWNS the other object, muhahaha).
	method AddObject:byte(obj:TObject)
	
		if (obj.GetOwner()) ..
			obj.GetOwner().RemoveObject(obj) 
		ListAddLast(m_localObjList, obj)
		return 1
	
	end method
	
	'// Remove an object from this object's local list.
	method RemoveObject:byte(obj:TObject)
	
		if (not obj.RemoveOwner()) ..
			return 0
		
		obj.SetPosX(-1)
		obj.SetPosY(-1)
		obj.SetPosZ(-1)
		
		ListRemove(m_localObjList, obj)
		
		return 1
	
	end method
	
	'// Set the owner of this object.
	method SetOwner:byte(obj:TObject)
	
		m_currentOwner = obj
		return 1
	
	end method
	
	'// Change owner to no owner.
	method RemoveOwner:byte()
	
		m_currentOwner = null
		return 1
	
	end method
	
	'// Set the description.
	method SetDescr(str:string); m_descr = str; end method
	
	'// Set the name.
	method SetName(str:string); m_name = str; end method
	
	'// Return the object-description.
	method GetDescr:string(); return m_descr; end method
	
	'// Return the name.
	method GetName:string(); return m_name; end method
	
	'// The HeartBeat of the object.
	method HeartBeat(); end method
	
	field m_id:int
	field m_posX:int = -1, m_posY:int = -1, m_posZ:int = -1
	field m_localObjList:TList = CreateList()
	
	'// This is the object (npc, room, player, etc) that currently owns this object.
	field m_currentOwner:TObject = null
	
	field m_descr:string
	field m_name:string

end type

'// TRoom is the object used for all rooms. All rooms are connected to a specific TRegion.
type TRoom extends TObject

	'// Add an exit to this room.
	method AddExit:byte(direction:string, locked:byte = 0, keyGUID:int = 0)
	
		local b:byte = false
		local newExit:TExit = new TExit
		
		newExit.direction = direction
		newExit.locked = locked
		newExit.keyGUID = keyGUID
		
		for local i:TExit = eachin m_exits
		
			if (i.direction = direction) then
			
				b = true
				exit
			
			end if
		
		next
		
		if b = false then
		
			ListAddLast(m_exits, newExit)
			return 1
		
		else
		
			return 0
		
		end if
	
	end method
	
	'// Return exits.
	method GetExits:TList(); return m_exits; end method
	
	'// Remove an exit from this room.
	method RemoveExit(direction:string); ListRemove(m_exits, direction); end method
	
	'// The HeartBeat of the room.
	method HeartBeat(); end method
	
	'// List of TExits.
	field m_exits:TList = CreateList()

end type

'// TExit is the object used for an exit from a room. You can make it lockable, using a specific key-object
'// (identified with it's guid).
type TExit

	field direction:string
	field locked:byte
	field keyGUID:int

end type



'// This is to access a room locally.
function AccessRoom:TRoom(w:TWorld, regionID:int, x:int, y:int, z:int)

	if (x and y and z and regionID) ..
		return w.AccessRegion(regionID).AccessRoom(x, y, z) ..
	else ..
		return null

end function

'// This is to access a region locally.
function AccessRegion:TRegion(w:TWorld, regionID:int)

	if (regionID) ..
		return w.AccessRegion(regionID) ..
	else ..
		return null

end function

'// This is to access an object locally.
function AccessObject:TObject(w:TWorld, regionID:int, GUID:int)

	if (GUID) then ..
		return  w.AccessRegion(regionID).AccessObject(GUID) ..
	else ..
		return null

end function
